﻿#region Usings
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Objects;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Windows.Threading;
using Defecter.Contract;
using DefectDBTypes;
#endregion

namespace Defecter.Gui.Access
{
	#region Class ClientAccess
	/// <summary>
	/// Provides a reference implementation of code required to manage the interaction with a <see cref="IClientContract"> client channel</see>
	/// </summary>
	public class ClientAccess: IClientCallbackContract, INotifyPropertyChanged
	{
		#region ClientAccess - Types
		#endregion

		#region ClientAccess - Fields
		private volatile DuplexChannelFactory<IClientContract> ca_channel_factory = null;
		private volatile IClientContract						ca_channel;
		private EndpointAddress											ca_endpoint_address;
		private uint																ca_endpoint_port;
		private Uri																	ca_endpoint_uri;
		private Binding															ca_binding;
		private System.Windows.Threading.Dispatcher	ca_owners_dispatcher;
		private string															ca_server;
		private Guid																ca_session_id;
		#endregion
		
		#region ClientAccess - Delegates and Events
		private delegate string AsyncAttachDelegate (out Guid sessionId);
		private delegate List<Client> AsyncGetClientsDelegate ();
		private delegate List<Trouble_Report> AsyncGetTroubleReportsDelegate ();
		private delegate List<TType> AsyncGetListDelegate<TType> ();
		private delegate string AsyncLogonDelegate (out UserRole userRole);

		public event EventHandler<GetListEventArgs<Client>> GetClientsCompleted;
		public event EventHandler<GetListEventArgs<Developer>> GetDevelopersCompleted;
		public event EventHandler<GetListEventArgs<Manager>> GetManagersCompleted;
		public event EventHandler<GetListEventArgs<Person>> GetPeopleCompleted;
		public event EventHandler<GetListEventArgs<Trouble_Report>> GetTroubleReportsCompleted;
		public event EventHandler<LogonLogoffEventArgs> LogonLogoffCompleted;
		public event PropertyChangedEventHandler PropertyChanged;

		#endregion

		#region ClientAccess - Properties
		/// <summary>
		/// Gets or creates and gets the associated Channel
		/// </summary>
		private IClientContract Channel
		{
			get
			{
				if (ca_channel == null)
					ca_channel = ChannelFactory.CreateChannel(EndpointAddress);
				return ca_channel;
			}
		}		/* property ClientAccess Channel */

		/// <summary>
		/// Gets or creates and gets the associated ChannelFactory
		/// </summary>
		private DuplexChannelFactory<IClientContract> ChannelFactory
		{
			get
			{
				if (ca_channel_factory == null)
				{
					ca_channel_factory = new DuplexChannelFactory<IClientContract>((IClientCallbackContract)this, ca_binding);
				}
				return ca_channel_factory;
			}
		}		/* property ClientAccess ChannelFactory */

		private EndpointAddress EndpointAddress
		{
			get
			{
				BasicHttpBinding binding_http;
				NetTcpBinding binding_tcp;
				NetNamedPipeBinding binding_pipe;

				if (ca_endpoint_address == null)
				{
					binding_http = ca_binding as BasicHttpBinding;
					if (binding_http != null)
					{
						ca_endpoint_address = new EndpointAddress(new Uri("http://" + ca_server + ":" + ca_endpoint_port.ToString() + "/DefecterService/Client"));
						goto function_exit;
					}
					binding_tcp = ca_binding as NetTcpBinding;
					if (binding_tcp != null)
					{
						ca_endpoint_address = new EndpointAddress(new Uri("net.tcp://" + ca_server + ":" + ca_endpoint_port.ToString() + "/DefecterService/Client"));
						goto function_exit;
					}
					binding_pipe = ca_binding as NetNamedPipeBinding;
					if (binding_pipe != null)
					{
						ca_endpoint_address = new EndpointAddress(new Uri("net.pipe://" + ca_server + ":" + ca_endpoint_port.ToString() + "/DefecterService/Client"));
						goto function_exit;
					}
				}
			function_exit:
				return ca_endpoint_address;
			}
		}		/* property ClientAccess EndpointAddress */

		public bool IsFaulted
		{
			get
			{
				return !(ca_channel != null &&
					((IClientChannel)ca_channel).State == CommunicationState.Opened);
			}
		}		/* property ClientAccess IsFaulted */

		private Guid SessionId
		{
			get
			{
				if (ca_session_id == Guid.Empty)
				{
					Attach();
					while (ca_session_id == Guid.Empty)
						System.Threading.Thread.Sleep(250);
				}
				return ca_session_id;
			}
		}		/* property ClientAccess SessionId */
		#endregion

		#region ClientAccess - Constructors
		public ClientAccess (string server, Binding binding, uint port,
			Dispatcher ownersDispatcher)
			: base()
		{
			ca_session_id = Guid.Empty;
			ca_server = server;
			ca_binding = binding;
			ca_endpoint_port = port;
			ca_owners_dispatcher = ownersDispatcher;
		}		/* constructor ClientAccess Item */
		#endregion

		#region ClientAccess - Methods
		public void Close ()
		{
			if (ca_channel != null)
			{
				try
				{
					((IClientChannel)ca_channel).Close(TimeSpan.FromSeconds(2));
				}
				catch (Exception ex)
				{
					Console.WriteLine(ex);
				}
				ca_channel = null;
			}
			if (ca_channel_factory != null)
			{
				try
				{
					ca_channel_factory.Close(TimeSpan.FromSeconds(1));
				}
				catch (Exception ex)
				{
					Console.WriteLine(ex);
				}
				ca_channel_factory = null;
			}
		}		/* method ClientAccess Close */
#if false
		public void RefeshSessionSummaries ()
		{
	//		CallRefreshSessionSummariesDelegate				call = null;

			Action call = delegate()
			{
				int																			retry_count = 3;

			retry:
				try
				{
					Channel.RefreshSessionSummaries();
				}
				catch (FaultException<WCFFault> fe)
				{
					throw fe.Detail.Reconstitute();
				}
				catch (CommunicationException cex)
				{
					ProcessCommunicationsException(cex, ref retry_count);
					goto retry;
				}
			}).BeginInvoke(new AsyncCallback(RefeshSessionSummariesCB), this);
			call.BeginInvoke(new AsyncCallback(RefeshSessionSummariesCB), this);
		}		/* method ClientAccess RefeshSessionSummaries */

		private void RefeshSessionSummariesCB (IAsyncResult result)
		{
			AsyncResult																ar = (AsyncResult)result;
			Exception																	rm_ex = null;
			PerformanceRecord													pr;

			try
			{
				((Action)ar.AsyncDelegate).EndInvoke(result);
			}
			catch (Exception ex)
			{
				Console.Write("Refresh exception: " + ex);
			}
		}		/* method PerformanceInterface RefeshSessionSummaries */
#endif
		private void OpenIfNeeded ()
		{
			if (((IClientChannel)Channel).State != CommunicationState.Opened)
			{
				Console.WriteLine("ClientAccess - Calling Open");
				try
				{
					((IClientChannel)Channel).Open();
				}
				catch (Exception ex)
				{
					Console.WriteLine("ClientAccess - Open Failed {0}",ex);
					throw ex;
				}
			}
		}		/* method ClientAccess OpenIfNeeded */

		/// <summary>
		/// 
		/// </summary>
		/// <param name="cex"></param>
		private void ProcessCommunicationsException (CommunicationException cex,
			ref int retryCount)
		{
			Console.WriteLine(cex);
			if (retryCount-- > 0)
			{
				if (cex is EndpointNotFoundException)
				{
					Close();
					System.Threading.Thread.Sleep(5 * 1000);
					OpenIfNeeded();
					goto function_exit;
				}
			}
			throw cex;
		function_exit:
			;
		}		/* method ClientAccess ProcessCommunicationsException */
#if false
		internal void StartSessionMonitoring ()
		{
			CallStartSessionMonitoringDelegate				call = null;

			call = delegate()
			{
				int																			retry_count = 3;

			retry:
				try
				{
					return Channel.StartMonitoring();
				}
				catch (FaultException<WCFFault> fe)
				{
					throw fe.Detail.Reconstitute();
				}
				catch (CommunicationException cex)
				{
					ProcessCommunicationsException(cex, ref retry_count);
					goto retry;
				}
			};
			call.BeginInvoke(new AsyncCallback(StartSessionMonitoringCB), this);
		}		/* method ClientAccess StartSessionMonitoring */

		private void StartSessionMonitoringCB (IAsyncResult result)
		{
			AsyncResult																ar = (AsyncResult)result;
			Exception																	rm_ex = null;
			ServerStatus															ss;

			try
			{
				ss = (ServerStatus)((CallStartSessionMonitoringDelegate)ar.AsyncDelegate).EndInvoke(result);
			}
			catch (Exception ex)
			{
				rm_ex = ex;
				ss = null;
			}
			try
			{
				if (StartStopSessionMonitoringCompleted != null)
					StartStopSessionMonitoringCompleted(Server, new StartStopSessionMonitoringEventArgs(true, ss, rm_ex));
			}
			catch (Exception ex)
			{
				LogTrace.Error(this, "Error encountered processing StartStopSessionMonitoringCompleted event", ex);
			}
		}		/* method ClientAccess StartSessionMonitoringCB */

		internal void StopSessionMonitoring ()
		{
			CallStopSessionMonitoringDelegate					call = null;

			call = delegate()
			{
				int retry_count = 3;

			retry:
				try
				{
					Channel.StopMonitoring();
				}
				catch (FaultException<WCFFault> fe)
				{
					throw fe.Detail.Reconstitute();
				}
				catch (CommunicationException cex)
				{
					ProcessCommunicationsException(cex, ref retry_count);
					goto retry;
				}
			};
			call.BeginInvoke(new AsyncCallback(StopSessionMonitoringCB), this);
		}		/* method ClientAccess StopSessionMonitoring */

		private void StopSessionMonitoringCB (IAsyncResult result)
		{
			AsyncResult																ar = (AsyncResult)result;
			Exception																	rm_ex = null;

			try
			{
				((CallStopSessionMonitoringDelegate)ar.AsyncDelegate).EndInvoke(result);
			}
			catch (Exception ex)
			{
				rm_ex = ex;
			}
			try
			{
				if (StartStopSessionMonitoringCompleted != null)
					StartStopSessionMonitoringCompleted(Server, new StartStopSessionMonitoringEventArgs(false, null, rm_ex));
			}
			catch (Exception ex)
			{
				LogTrace.Error(this, "Error encountered processing StartStopSessionMonitoringCompleted event", ex);
			}
		}		/* method ClientAccess StopSessionMonitoringCB */
#endif
		#endregion

		#region ClientAccess - Methods - Contract Calls
		#region ClientAccess - Methods - Contract Calls - People
		/// <summary>
		/// Makes an asynchronous call to return clients with not relations
		/// </summary>
		public void GetClients ()
		{
			GetClients(new string[0]);
		}		/* method ClientAccess GetClients */

		/// <summary>
		/// Makes an asynchronous call to return clients with with the specified relations
		/// </summary>
		/// <param name="includedRelations">string array of relations to be returned with the clients</param>
		public void GetClients (string[] includedRelations)
		{
			AsyncGetListDelegate<Client> call = delegate()
			{
				int retry_count = 3;

			retry:
				try
				{
					return Channel.GetClients(SessionId, includedRelations);
				}
				catch (FaultException<WCFFault> fe)
				{
					throw fe.Detail.Reconstitute();
				}
				catch (CommunicationException cex)
				{
					ProcessCommunicationsException(cex, ref retry_count);
					goto retry;
				}
			};
			call.BeginInvoke(new AsyncCallback(GetClientsCB), this);
		}		/* method ClientAccess GetClients */

		private void GetClientsCB (IAsyncResult result)
		{
			AsyncResult																ar = (AsyncResult)result;
			Exception																	rm_ex = null;
			List<Client>															items = null;

			if (!ca_owners_dispatcher.CheckAccess())
			{
				ca_owners_dispatcher.Invoke(new AsyncCallback(GetClientsCB), new object[] { result });
				return;
			}
			try
			{
				items = ((AsyncGetListDelegate<Client>)ar.AsyncDelegate).EndInvoke(result);
			}
			catch (Exception ex)
			{
				rm_ex = ex;
			}
			if (GetClientsCompleted != null)
			{
				GetClientsCompleted(this, new GetListEventArgs<Client>(rm_ex, false, null, null, items));
			}
		}		/* method ClientAccess GetClientsCB */

		public void GetDevelopers ()
		{
			GetDevelopers(new string[0]);
		}		/* method ClientAccess GetDevelopers */

		public void GetDevelopers (string[] includedRelations)
		{
			AsyncGetListDelegate<Developer> call = delegate()
			{
				int retry_count = 3;

			retry:
				try
				{
					return Channel.GetDevelopers(SessionId, includedRelations);
				}
				catch (FaultException<WCFFault> fe)
				{
					throw fe.Detail.Reconstitute();
				}
				catch (CommunicationException cex)
				{
					ProcessCommunicationsException(cex, ref retry_count);
					goto retry;
				}
			};
			call.BeginInvoke(new AsyncCallback(GetDevelopersCB), this);
		}		/* method ClientAccess GetDevelopers */

		private void GetDevelopersCB (IAsyncResult result)
		{
			AsyncResult																ar = (AsyncResult)result;
			Exception																	rm_ex = null;
			List<Developer>															items = null;

			if (!ca_owners_dispatcher.CheckAccess())
			{
				ca_owners_dispatcher.Invoke(new AsyncCallback(GetDevelopersCB), new object[] { result });
				return;
			}
			try
			{
				items = ((AsyncGetListDelegate<Developer>)ar.AsyncDelegate).EndInvoke(result);
			}
			catch (Exception ex)
			{
				rm_ex = ex;
			}
			if (GetDevelopersCompleted != null)
			{
				GetDevelopersCompleted(this, new GetListEventArgs<Developer>(rm_ex, false, null, null, items));
			}
		}		/* method ClientAccess GetDevelopersCB */

		public void GetManagers ()
		{
			GetManagers(new string[0]);
		}		/* method ClientAccess GetManagers */

		public void GetManagers (string[] includedRelations)
		{
			AsyncGetListDelegate<Manager> call = delegate()
			{
				int retry_count = 3;

			retry:
				try
				{
					return Channel.GetManagers(SessionId, includedRelations);
				}
				catch (FaultException<WCFFault> fe)
				{
					throw fe.Detail.Reconstitute();
				}
				catch (CommunicationException cex)
				{
					ProcessCommunicationsException(cex, ref retry_count);
					goto retry;
				}
			};
			call.BeginInvoke(new AsyncCallback(GetManagersCB), this);
		}		/* method ClientAccess GetManagers */

		private void GetManagersCB (IAsyncResult result)
		{
			AsyncResult																ar = (AsyncResult)result;
			Exception																	rm_ex = null;
			List<Manager>															items = null;

			if (!ca_owners_dispatcher.CheckAccess())
			{
				ca_owners_dispatcher.Invoke(new AsyncCallback(GetManagersCB), new object[] { result });
				return;
			}
			try
			{
				items = ((AsyncGetListDelegate<Manager>)ar.AsyncDelegate).EndInvoke(result);
			}
			catch (Exception ex)
			{
				rm_ex = ex;
			}
			if (GetManagersCompleted != null)
			{
				GetManagersCompleted(this, new GetListEventArgs<Manager>(rm_ex, false, null, null, items));
			}
		}		/* method ClientAccess GetManagersCB */

		/// <summary>
		/// Makes an asynchronous call to return people with not relations
		/// </summary>
		public void GetPeople ()
		{
			GetPeople(new string[0]);
		}		/* method ClientAccess GetPeople */

		/// <summary>
		/// Makes an asynchronous call to return people with with the specified relations
		/// </summary>
		/// <param name="includedRelations">string array of relations to be returned with the clients</param>
		public void GetPeople (string[] includedRelations)
		{
			AsyncGetListDelegate<Person> call = delegate()
			{
				int retry_count = 3;

			retry:
				try
				{
					return Channel.GetPeople(SessionId, includedRelations);
				}
				catch (FaultException<WCFFault> fe)
				{
					throw fe.Detail.Reconstitute();
				}
				catch (CommunicationException cex)
				{
					ProcessCommunicationsException(cex, ref retry_count);
					goto retry;
				}
			};
			call.BeginInvoke(new AsyncCallback(GetPeopleCB), this);
		}		/* method ClientAccess GetPeople */

		private void GetPeopleCB (IAsyncResult result)
		{
			AsyncResult																ar = (AsyncResult)result;
			Exception																	rm_ex = null;
			List<Person>															items = null;

			if (!ca_owners_dispatcher.CheckAccess())
			{
				ca_owners_dispatcher.Invoke(new AsyncCallback(GetPeopleCB), new object[] { result });
				return;
			}
			try
			{
				items = ((AsyncGetListDelegate<Person>)ar.AsyncDelegate).EndInvoke(result);
			}
			catch (Exception ex)
			{
				rm_ex = ex;
			}
			if (GetPeopleCompleted != null)
			{
				GetPeopleCompleted(this, new GetListEventArgs<Person>(rm_ex, false, null, null, items));
			}
		}		/* method ClientAccess GetPeopleCB */

		#endregion

		#region ClientAccess - Methods - Contract Calls - Housekeeping
		private void Attach ()
		{
			AsyncAttachDelegate call = delegate(out Guid sessionId)
			{
				int retry_count = 3;

			retry:
				try
				{
					return Channel.Attach(out sessionId);
				}
				catch (FaultException<WCFFault> fe)
				{
					throw fe.Detail.Reconstitute();
				}
				catch (CommunicationException cex)
				{
					ProcessCommunicationsException(cex, ref retry_count);
					goto retry;
				}
			};
			call.BeginInvoke(out ca_session_id, new AsyncCallback(AttachCB), this);
		}		/* method ClientAccess Attach */

		private void AttachCB (IAsyncResult result)
		{
			AsyncResult																ar = (AsyncResult)result;
			Exception																	rm_ex = null;
			string																		call_result = null;

			if (!ca_owners_dispatcher.CheckAccess())
			{
				ca_owners_dispatcher.Invoke(new AsyncCallback(AttachCB), new object[] { result });
				return;
			}
			try
			{
				call_result = ((AsyncAttachDelegate)ar.AsyncDelegate).EndInvoke(out ca_session_id, result);
			}
			catch (Exception ex)
			{
				rm_ex = ex;
			}
		}		/* method ClientAccess AttachCB */
		#endregion

		#region ClientAccess - Methods - Contract Calls - User
		public void Logoff ()
		{
			Func<string> call = delegate()
			{
				int retry_count = 3;

			retry:
				try
				{
					return Channel.Logoff(SessionId);
				}
				catch (FaultException<WCFFault> fe)
				{
					throw fe.Detail.Reconstitute();
				}
				catch (CommunicationException cex)
				{
					ProcessCommunicationsException(cex, ref retry_count);
					goto retry;
				}
			};
			call.BeginInvoke(new AsyncCallback(LogoffCB), this);
		}		/* method ClientAccess Logon */

		private void LogoffCB (IAsyncResult result)
		{
			AsyncResult																ar = (AsyncResult)result;
			Exception																	rm_ex = null;
			string																		call_result = null;

			if (!ca_owners_dispatcher.CheckAccess())
			{
				ca_owners_dispatcher.Invoke(new AsyncCallback(LogoffCB), new object[] { result });
				return;
			}
			try
			{
				call_result = ((Func<string>)ar.AsyncDelegate).EndInvoke(result);
			}
			catch (Exception ex)
			{
				rm_ex = ex;
			}
			try
			{
				if (LogonLogoffCompleted != null)
				{
					LogonLogoffCompleted(this, new LogonLogoffEventArgs(rm_ex, false, null, call_result, UserRole.None));
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine("Error encountered processing StartStopSessionMonitoringCompleted event");
				Console.WriteLine("Exception {0}", ex);
			}
		}		/* method ClientAccess LogonCB */

		public void Logon (string userName, string userPassword)
		{
			UserRole																	outer_user_role;

			AsyncLogonDelegate call = delegate(out UserRole user_role)
			{
				int retry_count = 3;

			retry:
				try
				{
					return Channel.Logon(SessionId,userName,userPassword,out user_role);
				}
				catch (FaultException<WCFFault> fe)
				{
					throw fe.Detail.Reconstitute();
				}
				catch (CommunicationException cex)
				{
					ProcessCommunicationsException(cex, ref retry_count);
					goto retry;
				}
			};
			call.BeginInvoke(out outer_user_role, new AsyncCallback(LogonCB), this);				
		}		/* method ClientAccess Logon */

		private void LogonCB (IAsyncResult result)
		{
			AsyncResult																ar = (AsyncResult)result;
			Exception																	rm_ex = null;
			string																		call_result = null;
			UserRole																	user_role = UserRole.None;

			if (! ca_owners_dispatcher.CheckAccess())
			{
				ca_owners_dispatcher.Invoke(new AsyncCallback(LogonCB), new object[] { result });
				return;
			}
			try
			{
				call_result = ((AsyncLogonDelegate)ar.AsyncDelegate).EndInvoke(out user_role,result);
			}
			catch (Exception ex)
			{ 
				rm_ex = ex;
			}
			try
			{
				if (LogonLogoffCompleted != null)
				{
					LogonLogoffCompleted(this, new LogonLogoffEventArgs(rm_ex, false, null, call_result, user_role));
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine("Error encountered processing StartStopSessionMonitoringCompleted event");
				Console.WriteLine("Exception {0}", ex);
			}
		}		/* method ClientAccess LogonCB */
		#endregion

		#region ClientAccess - Methods - Contract Calls - Trouble_Report
		/// <summary>
		/// Makes an asynchronous call to return all trouble reports
		/// </summary>
		/// <remarks>
		/// Calling this overload is the same as calling GetTroubleReports("Person");
		/// </remarks>
		public void GetTroubleReports ()
		{
			GetTroubleReports(typeof(Person));
		}		/* method ClientAccess GetTroubleReports */

		/// <summary>
		/// Makes an asynchronous call to return all trouble reports created by the specified person type
		/// </summary>
		/// <param name="ownerType">Type of the class of the creating user
		/// (eg. typeof(Client), typeof(Manager), typeof(Developer) or typeof(Person) )</param>
		/// <remarks>
		/// Call with ownerType = "Person" is the same as calling GetTroubleReports()
		/// </remarks>
		public void GetTroubleReports (Type ownerType)
		{
			GetTroubleReports(ownerType, new string[0]);
		}		/* method ClientAccess GetTroubleReports */

		/// <summary>
		/// Makes an asynchronous call to return all trouble reports created by the specified person type
		/// </summary>
		/// <param name="ownerType">Type of the class of the creating user
		/// (eg. typeof(Client), typeof(Manager), typeof(Developer) or typeof(Person) )</param>
		/// <param name="includedRelation">name of the relation to be returned with the trouble reports</param>
		/// <remarks>
		/// Call with ownerType = "Person" is the same as calling GetTroubleReports()
		/// </remarks>
		public void GetTroubleReports (Type ownerType, string includedRelation)
		{
			GetTroubleReports(ownerType,new string[] {includedRelation});
		}		/* method ClientAccess GetTroubleReports */

		/// <summary>
		/// Makes an asynchronous call to return all trouble reports created by the specified person type
		/// </summary>
		/// <param name="ownerType">Type of the class of the creating user
		/// (eg. typeof(Client), typeof(Manager), typeof(Developer) or typeof(Person) )</param>
		/// <param name="includedRelations">string array of relations to be returned with the trouble reports</param>
		/// <remarks>
		/// Call with ownerType = "Person" is the same as calling GetTroubleReports()
		/// </remarks>
		public void GetTroubleReports (Type ownerType, string [] includedRelations)
		{
			AsyncGetListDelegate<Trouble_Report> call = delegate()
			{
				int retry_count = 3;

			retry:
				try
				{
					return Channel.GetTroubleReports(SessionId, ownerType.Name, includedRelations);
				}
				catch (FaultException<WCFFault> fe)
				{
					throw fe.Detail.Reconstitute();
				}
				catch (CommunicationException cex)
				{
					ProcessCommunicationsException(cex, ref retry_count);
					goto retry;
				}
			};
			call.BeginInvoke(new AsyncCallback(GetTroubleReportsCB), this);
		}		/* method ClientAccess GetTroubleReports */

		private void GetTroubleReportsCB (IAsyncResult result)
		{
			AsyncResult																ar = (AsyncResult)result;
			Exception																	rm_ex = null;
			List<Trouble_Report>											items = null;

			if (!ca_owners_dispatcher.CheckAccess())
			{
				ca_owners_dispatcher.Invoke(new AsyncCallback(GetTroubleReportsCB), new object[] { result });
				return;
			}
			try
			{
				items = ((AsyncGetListDelegate<Trouble_Report>)ar.AsyncDelegate).EndInvoke(result);
			}
			catch (Exception ex)
			{
				rm_ex = ex;
			}
			if (GetTroubleReportsCompleted != null)
			{
				GetTroubleReportsCompleted(this, new GetListEventArgs<Trouble_Report>(rm_ex, false, null, null, items));
			}
		}		/* method ClientAccess AttachCB */

#if false
		public void GetTroubleReportsFrom<TObjectType> ()
			where TObjectType: class, IObjectWithChangeTracker
		{
			AsyncGetListDelegate<Trouble_Report> call = delegate()
			{
				int retry_count = 3;

			retry:
				try
				{
					return Channel.GetTroubleReportsFrom(SessionId,typeof(TObjectType).Name);
				}
				catch (FaultException<WCFFault> fe)
				{
					throw fe.Detail.Reconstitute();
				}
				catch (CommunicationException cex)
				{
					ProcessCommunicationsException(cex, ref retry_count);
					goto retry;
				}
			};
			call.BeginInvoke(new AsyncCallback(GetTroubleReportsCB), this);
		}		/* method ClientAccess GetTroubleReports */
#endif
		#endregion
		#endregion

		#region ClientAccess - Methods - IClientCallbackContract
		/// <summary>
		/// Notifies a client that a new defect has been added
		/// </summary>
		public void DefectAdded ()
		{
		}		/* method ClientAccess IClientCallbackContract.DefectAdded */
		#endregion

		#region ClientAccess - Methods - INotifyPropetyChanged
		private void FirePropertyChangedEvent (string propertyName)
		{
			if (PropertyChanged != null)
				PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
		}		/* method ClientAccess INotifyPropertyChanged.FirePropertyChangedEvent */
		#endregion
	}			/* class ClientAccess */
	#endregion

	#region Class ClientAccessCompletedEventArgs
	/// <summary>
	/// 
	/// </summary>
	/// <remarks>
	/// </remarks>
	public class ClientAccessCompletedEventArgs: AsyncCompletedEventArgs
	{
		#region ClientAccessCompletedEventArgs - Types
		#endregion

		#region ClientAccessCompletedEventArgs - Fields
		private string															cacea_result_message;
		#endregion

		#region ClientAccessCompletedEventArgs - Delegates and Events
		#endregion

		#region ClientAccessCompletedEventArgs - Properties
		public string ResultMessage
		{
			get
			{
				return cacea_result_message;
			}
		}		/* property ClientAccessCompletedEventArgs ResultMessage */
		#endregion

		#region ClientAccessCompletedEventArgs - Constructors
		public ClientAccessCompletedEventArgs (Exception error, bool canceled, object userState,
			string resultMessage)
			: base(error,canceled,userState)
		{
		}		/* constructor ClientAccessCompletedEventArgs */
		#endregion

		#region ClientAccessCompletedEventArgs - Methods
		#endregion
	}			/* class ClientAccessCompletedEventArgs */
	#endregion

	#region Class GetListEventArgs
	/// <summary>
	/// 
	/// </summary>
	/// <remarks>
	/// </remarks>
	public class GetListEventArgs<TType>: ClientAccessCompletedEventArgs
	{
		#region GetListEventArgs - Types
		#endregion

		#region GetListEventArgs - Fields
		private List<TType>													glea_items;
		#endregion

		#region GetListEventArgs - Delegates and Events
		#endregion

		#region GetListEventArgs - Properties
		public List<TType> Items
		{
			get
			{
				return glea_items;
			}
		}		/* property GetListEventArgs Items */
		#endregion

		#region GetListEventArgs - Constructors
		public GetListEventArgs (Exception error, bool canceled, object userState,
			string resultMessage, List<TType> items)
			: base(error, canceled, userState, resultMessage)
		{
			glea_items = items;
		}		/* constructor GetListEventArgs */
		#endregion

		#region GetListEventArgs - Methods
		#endregion
	}			/* class GetListEventArgs */
	#endregion

	#region Class LogonLogoffEventArgs
	/// <summary>
	/// 
	/// </summary>
	/// <remarks>
	/// </remarks>
	public class LogonLogoffEventArgs: ClientAccessCompletedEventArgs
	{
		#region LogonLogoffEventArgs - Types
		#endregion

		#region LogonLogoffEventArgs - Fields
		private UserRole														llea_user_role;
		#endregion

		#region LogonLogoffEventArgs - Delegates and Events
		#endregion

		#region LogonLogoffEventArgs - Properties
		public UserRole UserRole
		{
			get
			{
				return llea_user_role;
			}
		}		/* property LogonLogoffEventArgs UserRole */
		#endregion

		#region LogonLogoffEventArgs - Constructors
		public LogonLogoffEventArgs (Exception error, bool canceled, object userState,
			string resultMessage, UserRole userRole)
			: base(error, canceled, userState, resultMessage)
		{
			llea_user_role = userRole;
		}		/* constructor LogonLogoffEventArgs */
		#endregion

		#region LogonLogoffEventArgs - Methods
		#endregion
	}			/* class LogonLogoffEventArgs */
	#endregion
}